From 2fa58fe96f5824048ad54376689a1936ef2d99d0 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk[kaf24]" Date: Mon, 19 Jan 2004 19:41:53 +0000 Subject: [PATCH] bitkeeper revision 1.682 (400c3301usqWi45kB_H-oz2aBEtHyw) maw-vd-rc2.patch --- .rootkeys | 3 + tools/examples/vd_delete.py | 3 + tools/examples/vd_freespace.py | 11 ++ tools/examples/vd_list.py | 10 ++ tools/examples/vd_refresh.py | 2 + tools/examples/vd_undelete.py | 32 ++++ tools/xc/py/XenoUtil.py | 284 +++++++++++++++++++++++++++++++-- 7 files changed, 328 insertions(+), 17 deletions(-) create mode 100644 tools/examples/vd_freespace.py create mode 100644 tools/examples/vd_list.py create mode 100644 tools/examples/vd_undelete.py diff --git a/.rootkeys b/.rootkeys index a4fd7de824..3178fdeae6 100644 --- a/.rootkeys +++ b/.rootkeys @@ -53,7 +53,10 @@ 40083bb4LeyQyL-0riaV3UYDfHkl5g tools/examples/vd_create.py 40083bb4TmKs8pcFkOcJj1bKn3zcmg tools/examples/vd_delete.py 40083bb4u9Od6ujgect6mrxWfkk1pQ tools/examples/vd_format.py +400c33000SvWkdG92u4Bvdu6BPjGPw tools/examples/vd_freespace.py +400c3300jb_Ufz2kWsovGKNoDPEf-A tools/examples/vd_list.py 40083bb4NhDpKiYTrebI3ZjX__oI_w tools/examples/vd_refresh.py +400c33001-uDKTfHBchTKUwuMFcqTA tools/examples/vd_undelete.py 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README diff --git a/tools/examples/vd_delete.py b/tools/examples/vd_delete.py index ad7a210b14..ca2a3fd19f 100644 --- a/tools/examples/vd_delete.py +++ b/tools/examples/vd_delete.py @@ -18,3 +18,6 @@ else: print "Deleting a virtual disk with ID: " + id ret = XenoUtil.vd_delete(id) + +if ret: + print "Deletion failed: invalid ID, or disk already expired / deleted" diff --git a/tools/examples/vd_freespace.py b/tools/examples/vd_freespace.py new file mode 100644 index 0000000000..5ebc76260f --- /dev/null +++ b/tools/examples/vd_freespace.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +# +# vd_freespace.py +# +# Prints out the amount of free space (in megabytes) for creating virtual disks. +# + +import XenoUtil + +print XenoUtil.vd_freespace() diff --git a/tools/examples/vd_list.py b/tools/examples/vd_list.py new file mode 100644 index 0000000000..6be8ccbcbc --- /dev/null +++ b/tools/examples/vd_list.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# +# vd_list.py - use this to list all the unexpired virtual disks in the +# virtual disk database +# + +import XenoUtil + +print XenoUtil.vd_list() diff --git a/tools/examples/vd_refresh.py b/tools/examples/vd_refresh.py index cfe7f4a2aa..afbdfb8ea8 100644 --- a/tools/examples/vd_refresh.py +++ b/tools/examples/vd_refresh.py @@ -29,3 +29,5 @@ print "Expiry time (seconds from now): " + sys.argv[2] ret = XenoUtil.vd_refresh(id, expiry_time) +if ret: + print "Refresh failed, non-existent virtual disk or disk is expired / deleted" diff --git a/tools/examples/vd_undelete.py b/tools/examples/vd_undelete.py new file mode 100644 index 0000000000..d43c773c36 --- /dev/null +++ b/tools/examples/vd_undelete.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# +# vd_undelete.py vdisk_id [ new_expiry ] +# +# Undeletes a VD and, optionally, sets a new expiry time or disables +# expiry if the time value is zero (default) +# + +import XenoUtil, sys + +if len(sys.argv) < 2: + print >>sys.stderr, "Usage: " + sys.argv[0] + """ vdisk_id [ new_expiry ] + vdisk_id - the identifier of the deleted VD + new_expiry - optionally the new expiry time in seconds from now (0 + for never expire - which is the default) + + VDs can currently only be undeleted if it is safe to do so, + i.e. if none of their space has been reallocated. + """ + +vdisk_id = sys.argv[1] + +if len(sys.argv) == 3: + expiry = int(sys.argv[2]) +else: + expiry = 0 + +if XenoUtil.vd_undelete(vdisk_id, expiry): + print "Undelete operation failed for virtual disk: " + vdisk_id +else: + print "Undelete operation succeeded for virtual disk: " + vdisk_id diff --git a/tools/xc/py/XenoUtil.py b/tools/xc/py/XenoUtil.py index c37aaaf8f2..abf320dab5 100644 --- a/tools/xc/py/XenoUtil.py +++ b/tools/xc/py/XenoUtil.py @@ -219,6 +219,7 @@ def vd_format(partition, extent_size_mb): cx.close() return 0 + def vd_create(size_mb, expiry): """Create a new virtual disk. size_mb [int]: size in megabytes for the new virtual disk @@ -252,10 +253,10 @@ def vd_create(size_mb, expiry): if expiry: expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" - expires = 1; + expires = 1 else: expiry_ts = "NULL" - expires = 0; + expires = 0 # we'll use this to build the SQL statement we want building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \ @@ -269,6 +270,7 @@ def vd_create(size_mb, expiry): if not row: cx.close() return -1 + (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row allocated += extent_size @@ -310,6 +312,19 @@ def vd_lookup(id): cx = sqlite.connect(VD_DB_FILE) cu = cx.cursor() + cu.execute("-- types int") + cu.execute("""SELECT COUNT(*) + FROM vdisks + WHERE (expiry_time > datetime('now') OR NOT expires) + AND vdisk_id = """ + id) + count, = cu.fetchone() + + if not count: + cx.close() + return -1 + + cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id) + real_size, = cu.fetchone() # This query tells PySQLite how to convert the data returned from the # following query - the use of the multiplication confuses it otherwise ;-) @@ -326,11 +341,10 @@ def vd_lookup(id): FROM vdisk_extents NATURAL JOIN vdisks NATURAL JOIN vdisk_part - WHERE (expiry_time > datetime('now') OR not expires) - AND vdisk_extents.vdisk_id = """ + id + WHERE vdisk_extents.vdisk_id = """ + id ) - ret = cu.fetchall() + extent_tuples = cu.fetchall() # use this function to map the results from the database into a dict # list of extents, for consistency with the rest of the code @@ -341,13 +355,204 @@ def vd_lookup(id): cx.commit() cx.close() - return map(transform, ret) # transforms the tuples into dicts to return + extent_dicts = map(transform, extent_tuples) + + # calculate the over-allocation in sectors (happens because + # we allocate whole extents) + allocated_size = 0 + for i in extent_dicts: + allocated_size += i['nr_sectors'] + + over_allocation = allocated_size - real_size + + # trim down the last extent's length so the resulting VBD will be the + # size requested, rather than being rounded up to the nearest extent + extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation + + return extent_dicts + + +def vd_enlarge(vdisk_id, extra_size_mb): + """Create a new virtual disk. + vdisk_id [string] : ID of the virtual disk to enlarge + extra_size_mb [int]: size in megabytes to increase the allocation by + returns [int] : 0 on success, otherwise non-zero + """ + + if not os.path.isfile(VD_DB_FILE): + __vd_no_database() + + cx = sqlite.connect(VD_DB_FILE) + cu = cx.cursor() + + extra_size = extra_size_mb * 2048 + + cu.execute("-- types int") + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id + + " AND (expiry_time > datetime('now') OR NOT expires)") + count, = cu.fetchone() + + if not count: # no such vdisk + cx.close() + return -1 + + cu.execute("-- types int") + cu.execute("""SELECT SUM(extent_size) + FROM vdisks NATURAL JOIN vdisk_extents + NATURAL JOIN vdisk_part + WHERE vdisks.vdisk_id = """ + vdisk_id) + + real_size, = cu.fetchone() # get the true allocated size + + cu.execute("-- types int") + cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) + + old_size, = cu.fetchone() + + + cu.execute("--- types int") + cu.execute("""SELECT MAX(vdisk_extent_no) + FROM vdisk_extents + WHERE vdisk_id = """ + vdisk_id) + + counter = cu.fetchone()[0] + 1 # this stores the extent numbers + + + # because of the extent-based allocation, the VD may already have more + # allocated space than they asked for. Find out how much we really + # need to add. + add_size = extra_size + old_size - real_size + + # fetch a list of extents from the expired disks, along with information + # about their size + cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no, + vdisk_extents.part_id, extent_size + FROM vdisk_extents NATURAL JOIN vdisks + NATURAL JOIN vdisk_part + WHERE expires AND expiry_time < datetime('now') + ORDER BY expiry_time asc, vdisk_extent_no desc + """) # aims to reuse the last extents + # from the longest-expired disks first + + allocated = 0 + + building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\ + + " WHERE vdisk_id = " + vdisk_id + "; " + + while allocated < add_size: + row = cu.fetchone() + if not row: + cx.close() + return -1 + + (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row + allocated += extent_size + building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id \ + + ", " + "vdisk_extent_no = " + str(counter) \ + + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \ + + " AND vdisk_id = " + str(dead_vd_id) + "; " + + counter += 1 + + + # this will execute the SQL query we build to store details of the new + # virtual disk and allocate space to it print building_sql + cu.execute(building_sql) + + cx.commit() + cx.close() + return 0 + + +def vd_undelete(vdisk_id, expiry_time): + """Create a new virtual disk. + vdisk_id [int]: size in megabytes for the new virtual disk + expiry_time [int]: expiry time, in seconds from now + returns [int]: zero on success, non-zero on failure + """ + + if not os.path.isfile(VD_DB_FILE): + __vd_no_database() + + cx = sqlite.connect(VD_DB_FILE) + cu = cx.cursor() + + cu.execute("-- types int") + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id) + count, = cu.fetchone() + + if not count: + cx.close() + return -1 + + cu.execute("-- types int") + cu.execute("""SELECT SUM(extent_size) + FROM vdisks NATURAL JOIN vdisk_extents + NATURAL JOIN vdisk_part + WHERE vdisks.vdisk_id = """ + vdisk_id) + + real_size, = cu.fetchone() # get the true allocated size + + + cu.execute("-- types int") + cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id) + + old_size, = cu.fetchone() + + if real_size < old_size: + cx.close() + return -1 + + if expiry_time == 0: + expires = '0' + else: + expires = '1' + + # this will execute the SQL query we build to store details of the new + # virtual disk and allocate space to it print building_sql + cu.execute("UPDATE vdisks SET expiry_time = datetime('now','" + + str(expiry_time) + " seconds'), expires = " + expires + + " WHERE vdisk_id = " + vdisk_id) + + cx.commit() + cx.close() + return 0 + + + + +def vd_list(): + """Lists all the virtual disks registered in the system. + returns [list of dicts] + """ + + if not os.path.isfile(VD_DB_FILE): + __vd_no_database() + + cx = sqlite.connect(VD_DB_FILE) + cu = cx.cursor() + + cu.execute("""SELECT vdisk_id, size, expires, expiry_time + FROM vdisks + WHERE (NOT expires) OR expiry_time > datetime('now') + """) + + ret = cu.fetchall() + + cx.close() + + def makedicts((vdisk_id, size, expires, expiry_time)): + return { 'vdisk_id' : str(vdisk_id), 'size': size, + 'expires' : expires, 'expiry_time' : expiry_time } + + return map(makedicts, ret) def vd_refresh(id, expiry): """Change the expiry time of a virtual disk. - id [string]: a virtual disk identifier - expiry [int]: expiry time in seconds from now (0 = never expire) + id [string] : a virtual disk identifier + expiry [int] : expiry time in seconds from now (0 = never expire) + returns [int]: zero on success, non-zero on failure """ if not os.path.isfile(VD_DB_FILE): @@ -356,6 +561,15 @@ def vd_refresh(id, expiry): cx = sqlite.connect(VD_DB_FILE) cu = cx.cursor() + cu.execute("-- types int") + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id + + " AND (expiry_time > datetime('now') OR NOT expires)") + count, = cu.fetchone() + + if not count: + cx.close() + return -1 + if expiry: expires = 1 expiry_ts = "datetime('now', '" + str(expiry) + " seconds')" @@ -365,17 +579,20 @@ def vd_refresh(id, expiry): cu.execute("UPDATE vdisks SET expires = " + str(expires) + ", expiry_time = " + expiry_ts - + " WHERE vdisk_id = " + id) + + " WHERE (expiry_time > datetime('now') OR NOT expires)" + + " AND vdisk_id = " + id) cx.commit() cx.close() - return + return 0 + def vd_delete(id): - """Deletes a Virtual Disk, making its extents available for future - virtual disks. - [id] identifier for the virtual disk to delete + """Deletes a Virtual Disk, making its extents available for future VDs. + id [string] : identifier for the virtual disk to delete + returns [int] : 0 on success, -1 on failure (VD not found + or already deleted) """ if not os.path.isfile(VD_DB_FILE): @@ -384,13 +601,46 @@ def vd_delete(id): cx = sqlite.connect(VD_DB_FILE) cu = cx.cursor() + cu.execute("-- types int") + cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id + + " AND (expiry_time > datetime('now') OR NOT expires)") + count, = cu.fetchone() + + if not count: + cx.close() + return -1 + cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')" + " WHERE vdisk_id = " + id) cx.commit() cx.close() - return + return 0 + + +def vd_freespace(): + """Returns the amount of free space available for new virtual disks, in MB + returns [int] : free space for VDs in MB + """ + + if not os.path.isfile(VD_DB_FILE): + __vd_no_database() + + cx = sqlite.connect(VD_DB_FILE) + cu = cx.cursor() + + cu.execute("-- types int") + + cu.execute("""SELECT SUM(extent_size) + FROM vdisks NATURAL JOIN vdisk_extents + NATURAL JOIN vdisk_part + WHERE expiry_time <= datetime('now') AND expires""") + + sum, = cu.fetchone() + + return sum / 2048 + def vd_init_db(path): """Initialise the VD SQLite database @@ -461,12 +711,12 @@ def vd_extents_validate(new_extents,new_writeable): this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd']) for vbd_ext in this_vbd_extents: vbd_ext['writeable'] = vbd['writeable'] - old_extents.append(vbd_ext); - + old_extents.append(vbd_ext) + ##### Now scan /proc/mounts for compile a list of extents corresponding to ##### any devices mounted in DOM0. This list is added on to old_extents - regexp = re.compile("/dev/(\S*) \S* \S* (..).*"); + regexp = re.compile("/dev/(\S*) \S* \S* (..).*") fd = open('/proc/mounts', "r") while True: -- 2.30.2